
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "reflecxx.h"

struct {
    const char *plain;
    const char *escaped;
} test_pairs[] = {
    { "", "\"\"" },
    { "Hello, World!", "\"Hello, World!\"" },
    { "Leeloo\n", "\"Leeloo\\n\"" },
    { "\tDallas\\Leeloo\n  \"Multi-Pass\"\r\n",
      "\"\\tDallas\\\\Leeloo\\n  \\\"Multi-Pass\\\"\\r\\n\"" },
    { "WTF is \f?", "\"WTF is \\f?\"" },
    { "\336a", "\"\\u00dea\"" },
    { NULL }
};

static char in_buffer[1024];
static int did_realloc = 0;
static int did_free = 0;

static void *in_reflecxx_malloc(size_t s)
{
    return in_buffer;
}

static void in_reflecxx_free(void *m)
{
    assert(m == in_buffer);

    did_free = 1;
}

static void *in_reflecxx_realloc(void *m, size_t s)
{
    assert(m == in_buffer);

    did_realloc = 1;
    
    return NULL;
}

int main(int argc, char *argv[])
{
    int lpc, retval = EXIT_SUCCESS;

    assert(reflecxx_escape(NULL) == NULL);

    for (lpc = 0; test_pairs[lpc].plain != NULL; lpc++) {
	char *val;
	int len;

	val = reflecxx_escape(test_pairs[lpc].plain);
	assert(val != NULL);
	assert(strcmp(val, test_pairs[lpc].escaped) == 0);
	reflecxx_free(val);

	len = strlen(test_pairs[lpc].escaped);
	val = reflecxx_unescape(test_pairs[lpc].escaped, &len);
	assert(val != NULL);
	assert(len == strlen(test_pairs[lpc].escaped));
	assert(strcmp(val, test_pairs[lpc].plain) == 0);
	reflecxx_free(val);
    }

    for (lpc = 0; lpc < 100; lpc++) {
	char buffer[128], *esc, *pl;
	int lpc2, len;

	for (lpc2 = 0; lpc2 < sizeof(buffer) - 1; lpc2++) {
	    while ((buffer[lpc2] = random()) == 0);
	}
	buffer[lpc2] = '\0';

	esc = reflecxx_escape(buffer);
	assert(esc != NULL);
	len = strlen(esc);
	pl = reflecxx_unescape(esc, &len);
	assert(len == strlen(esc));
	assert(strcmp(buffer, pl) == 0);

	reflecxx_free(esc);
	reflecxx_free(pl);
    }

    {
	int len;
	
	assert(reflecxx_unescape("\"\\u00\"", &len) == NULL);
    }

    reflecxx_malloc = in_reflecxx_malloc;
    reflecxx_free = in_reflecxx_free;
    reflecxx_realloc = in_reflecxx_realloc;

    assert(reflecxx_escape("\n\n\n\n\n\n\n\n\n\n") == NULL);
    assert(did_realloc == 1);
    assert(did_free == 1);
    
    return retval;
}
